/*
 * Copyright (C) 2009 aileron.cc
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package cc.aileron.dao.db.sql;

import static cc.aileron.commons.util.CastUtils.cast;
import static cc.aileron.template.flow.FlowCategory.DEF;
import static cc.aileron.template.flow.FlowCategory.EACH;

import java.util.HashMap;

import cc.aileron.accessor.PojoAccessor;
import cc.aileron.accessor.PojoAccessorValueNotFoundException;
import cc.aileron.accessor.PojoPropertiesNotFoundException;
import cc.aileron.template.context.TemplateContext;
import cc.aileron.template.flow.FlowCategory;
import cc.aileron.template.flow.FlowDefMethod;
import cc.aileron.template.flow.FlowEachMethod;
import cc.aileron.template.flow.FlowMethodProvider;
import cc.aileron.template.flow.FlowMethodProviderMap;

import com.google.inject.Inject;
import com.google.inject.Singleton;

/**
 * @author aileron
 */
@Singleton
public class SqlFlowMethodProviderMap implements FlowMethodProviderMap
{
	@Override
	public FlowMethodProvider get(final FlowCategory category)
	{
		return map.get(category);
	}

	/**
	 * @param def
	 * @param each
	 */
	@Inject
	public SqlFlowMethodProviderMap(final FlowDef def, final FlowEach each)
	{
		map = new HashMap<FlowCategory, FlowMethodProvider>();
		map.put(DEF, def);
		map.put(EACH, each);
	}

	private final HashMap<FlowCategory, FlowMethodProvider> map;
}

/**
 * def
 *
 * @author aileron
 *
 */
class FlowDef implements FlowMethodProvider
{
	public FlowDefMethod get(final String arg)
	{
		final String[] args = arg.split(" ");
		final String name = args[0];
		final boolean isNo = args.length == 2 ? args[1].equals("!") : false;
		return new FlowDefMethod()
		{
			public boolean call(final TemplateContext context)
					throws PojoAccessorValueNotFoundException,
					PojoPropertiesNotFoundException
			{
				final PojoAccessor<Object> accessor = cast(context
						.getAccessor());
				final boolean result = accessor.to(name).value(Boolean.class);
				return isNo ? !result : result;
			}
		};
	}
}

/**
 * each
 *
 * @author aileron
 *
 */
class FlowEach implements FlowMethodProvider
{
	public FlowEachMethod get(final String args)
	{
		final String[] token = args.split(" ");
		final String key = token[0];
		final String indexKey;
		if (token.length >= 2)
		{
			indexKey = token[1];
		}
		else
		{
			indexKey = null;
		}
		return new FlowEachMethod()
		{
			public Iterable<PojoAccessor<Object>> call(
					final TemplateContext context)
					throws PojoAccessorValueNotFoundException,
					PojoPropertiesNotFoundException
			{
				return context.getAccessor().to(key).accessorIterable(
						Object.class);
			}

			@Override
			public int startCount(final TemplateContext context)
					throws PojoAccessorValueNotFoundException,
					PojoPropertiesNotFoundException
			{
				if (indexKey == null)
				{
					return 0;
				}
				return context.getAccessor().to(indexKey).value(Number.class)
						.intValue();
			}
		};
	}
}